#include<iostream>
#include <pthread.h>
#include<iomanip>
#include <iostream>
#include<vector>
#include<semaphore.h>

#include<sys/time.h>
using namespace std;
int taskNum = 1;
int pThreadNum = 1;
int n;
float** m;
void generate()
{
    for (int i = 0; i < n; i++)
    {
        m[i][i] = 1.0;
        for (int p = i + 1; p < n; p++)
        {
            m[i][p] = rand() % 100 + 1;
        }
    }
    for (int k = 0; k < n; k++)
    {
        for (int i = k + 1; i < n; i++)
        {
            for (int p = 0; p < n; p++)
            {
                m[i][p] += m[k][p];
            }
        }
    }
}
void show()
{
    for (int i = 0; i < n; i++)
    {
        for (int p = 0; p < n; p++)
        {
            cout << setw(5) << m[i][p] << " ";
        }
        cout << endl;
    }
}
void commonGaosi()
{
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            m[i][j] /= m[i][i];
        }
        for (int k = i + 1; k < n; k++)
        {
            for (int j = i + 1; j < n; j++)
            {
                m[k][j] -= m[i][j] * m[k][i];
            }
            m[k][i] = 0;
        }
    }
}
void init()
{
    m = new float* [n];
    for (int p = 0; p < n; p++)
    {
        m[p] = new float[n];
        for (int q = 0; q < n; q++)
        {
            m[p][q] = 0.0;
        }
    }
    generate();
}



typedef struct
{
    int t_id; 
}threadParam_t;


sem_t sem_leader;
sem_t* sem_Divsion;
sem_t* sem_Elimination;


void* threadFunc(void* param)
{
    threadParam_t* p = (threadParam_t*)param;
    int t_id = p->t_id;
    int begin = 0;


    for (int k = 0; k < n; k++)
    {
        taskNum = (n - k) / pThreadNum + 1;
        if (t_id == 0)
        {
            for (int j = k + 1; j < n; j++)
                m[k][j] = m[k][j] / m[k][k];
            m[k][k] = 1.0;
        }
        else
            sem_wait(&sem_Divsion[t_id - 1]);

        if (t_id == 0)
            for (int i = 0; i < pThreadNum - 1; i++)
                sem_post(&sem_Divsion[i]);

        begin = k + t_id * taskNum + 1;

        for (int i = begin; i < n; i += pThreadNum)
        {
            for (int j = k + 1; j < n; j++)
                m[i][j] = m[i][j] - m[i][k] * m[k][j];
            m[i][k] = 0;
        }

        if (t_id == 0)
        {
            for (int i = 0; i < pThreadNum - 1; i++)
                sem_wait(&sem_leader);
            for (int i = 0; i < pThreadNum - 1; i++)
                sem_post(&sem_Elimination[i]);
        }
        else
        {
            sem_post(&sem_leader);
            sem_wait(&sem_Elimination[t_id - 1]);
        }
    }


    pthread_exit(NULL);
}





void gaosi(int type)
{
    sem_init(&sem_leader, 0, 0);
    for (int i = 0; i < pThreadNum; i++)
    {
        sem_init(&sem_Divsion[i], 0, 0);
        sem_init(&sem_Elimination[i], 0, 0);
    }
    pthread_t* handle = new pthread_t[pThreadNum];
    threadParam_t* param = new threadParam_t[pThreadNum];
    for (int id = 0; id < pThreadNum; id++)
    {
        param[id].t_id = id;
        switch (type)
        {
        case 0:
            pthread_create(&handle[id], NULL, threadFunc, (void*)&param[id]);
            break;
        case 1:
            pthread_create(&handle[id], NULL, ssethreadFunc, (void*)&param[id]);
            break;
        case 2:
            pthread_create(&handle[id], NULL, avxthreadFunc, (void*)&param[id]);
            break;
        }
    }


    for (int id = 0; id < pThreadNum; id++)
        pthread_join(handle[id], NULL);

}





int main()
{
    pThreadNum = 10;
    sem_Divsion = new sem_t[pThreadNum - 1];
    sem_Elimination = new sem_t[pThreadNum - 1];


    struct timeval t1, t2;
    double timeuse;

    for (int i = 1; i <= 15; i++)
    {
        n = i * 200;
        init();
        gettimeofday(&t1, NULL);
        gaosi(0);
        gaosi(1);
        gaosi(2);
        commonGaosi();
        gettimeofday(&t2, NULL);
        timeuse = (t2.tv_sec - t1.tv_sec) + (double)(t2.tv_usec - t1.tv_usec) / 1000000.0;
        cout << timeuse << endl;
    }
    sem_destroy(&sem_leader);
    for (int i = 0; i < pThreadNum; i++)
    {
        sem_destroy(&sem_Divsion[i]);
        sem_destroy(&sem_Elimination[i]);
    }
    return 0;
}